import { request, gql } from "graphql-request";
import webconfig from "../webconfig";
import axios from "./axios";
import store from "../utils/store";
import * as antdHelper from "../utils/antd-helper";
import { getFileType, getFileExt, getFileTypeId } from "../utils/file-helper";
import { formatterSizeStr, formatBalanceStr, formatPicUrl } from "../utils/formatter";

//common
function getHeaders(isNeedAuth) {
	if (!isNeedAuth) return;
	return {
		Authorization: "Bearer " + store.get("token")
	};
}
async function got(document, isNeedAuth) {
	let ret = { msg: '' };
	try {
		let data = await request(window.apiURL || "https://decloud.cess.cloud/api/", document, null, getHeaders(isNeedAuth));
		if (typeof data == 'string') {
			data = JSON.parse(data);
		}
		if (!data.errors) {
			ret = { msg: "ok", data };
		} else if (data.errors && data.errors.length > 0) {
			ret = { msg: data.errors[0].message };
		} else {
			console.error(data);
		}
	} catch (e) {
		ret.msg = progressError(e);
	} finally {
		return ret;
	}
}
function progressError(e) {
	console.log(e);
	let errMsg = e.message;
	if (e.message.includes("Unauthorized")) {
		errMsg = "Please login again";
		setTimeout(function () {
			if (window.navigate) {
				window.navigate("/login");
			}
		}, 300);
	} else {
		let i = e.message.indexOf("{");
		if (i > 0) {
			i = i - 2;
			errMsg = e.message.slice(0, i);
		}
	}
	return errMsg.replace("Error:", "");
}
function makePager(params) {
	let pageindex = params.pageindex || 1;
	let pagesize = params.pagesize || 20;
	let after = pagesize * (pageindex - 1);
	return `pagination:{after: "${after}", first: ${pagesize}}`;
}
function accountTypeToInt(type) {
	return type == 'email' ? 1 : type == 'evm' ? 3 : 2;
}
function identityToInt(identity) {
	return identity.includes('@') ? 1 : identity.indexOf('cX') === 0 ? 2 : 3;
}
function storeUserInfo(info) {
	store.set("token", info.token);
	if (info.inviteCode) {
		store.set("inviteCode", info.inviteCode);
	}
	store.set("userId", info.id);
	store.set("identity", info.identity);
	if (info.address) {
		store.set("address", info.address);
		let account = store.get("account")
		if (!account || Object.keys(account).length == 0) {
			account = info;
		}
		// account.address = info.address;
		store.set("account", account);
		store.set("addr", info.address);
	}
	if (info.email) {
		store.set("email", info.email);
	}
	store.set("accountType", info.accountTypeId == 1 ? "email" : info.accountTypeId == 3 ? "evm" : "wallet");
}
export function setCessAddr(addr) {
	store.set('cess-addr', addr);
}
export function getCessAddr() {
	store.get('cess-addr');
}
//backend
export async function login(identity, password, remember) {
	const document = gql`
		{
			login(form: { identity:"${identity}", password: "${password}"}) {
				token
				id
				identity
			}
		}
	`;
	let ret = await got(document);
	if (!ret) return false;
	if (ret.msg != "ok" || !ret.data.login || !ret.data.login.token) {
		return false;
	}
	store.set("token", ret.data.login.token);
	store.set("accountId", ret.data.login.id);
	store.set("identity", identity);
	if (remember) {
		store.set("account", {
			identity,
			password
		});
	}
	return true;
}
export async function changePassword(password, newPassword) {
	const document = gql`
		mutation {
			changePassword(form: { password: "${password}", newPassword: "${newPassword}", confirmPassword: "${newPassword}" })
		}
	`;
	let ret = await got(document, true);
	return ret;
}
export async function decloudStatistics() {
	const document = gql`
		{
			decloudStatistics {
				totalUsers {
					dateStr
					value
				}
				newUsersLast24Hr {
					dateStr
					value
				}
				newUsersLastWeek {
					dateStr
					value
				}
				soldStorageSpace
				soldStorageSpaceHistory
				invitedUsers
				totalIncome {
					dateStr
					value
				}
				todayIncome {
					dateStr
					value
				}
				weeklyIncome {
					dateStr
					value
				}
				inviteUserSubsidies
				inviteBonus
			}
		}
	`;
	let ret = await got(document, true);
	if (!ret) return ret;
	return ret.data.decloudStatistics;
}
// only for admin
export async function userDetail(email, address) {
	let filter = {};
	if (email) {
		filter = `{email:"${email}"}`;
	} else {
		filter = `{address:"${address}"}`;
	}
	let ret = await userList({
		filter,
		pageindex: 1,
		pagesize: 1
	});
	if (!ret) return ret;
	if (ret.msg != "ok") {
		return ret;
	}
	if (ret.data.length > 0) {
		ret.data = ret.data[0];
	} else {
		ret = { msg: "user not found" };
	}
	return ret;
}
// only for admin
export async function userList(params) {
	let pagination = makePager(params);
	const document = gql`
		{
			userList(filter: ${params.filter},${pagination}) {
				totalRows
				userList {
					pageInfo {
						hasPreviousPage
						hasNextPage
						startCursor
						endCursor
					}				
					nodes {
						totalInvited
						accountType {
							id
							name
							isAdmin
						}
						account {
							id
							identity
							email
              address
							accountTypeId
							myInviteCode
							creationTime
							discount
							invitedBy
						}
						storage {
							id
							accountId
							size
							price
						}
					}
				}
			}
		}
	`;
	let ret = await got(document, true);
	if (!ret) return ret;
	let data = ret.data.userList.userList.nodes.map(t => {
		let o = t.account;
		o.totalInvited = t.totalInvited;
		o.accountTypeStr = t.accountType.name;
		o.isAdmin = t.accountType?.isAdmin;
		o.storageSize = t.storage?.size;
		o.key = o.id;
		return o;
	});

	return { msg: "ok", data, total: ret.data.userList.totalRows };
}
export async function operation(params) {
	let pagination = makePager(params);
	const document = gql`
		{
			operation(filter: { fileType: "${params.filter}" },${pagination}) {
				totalRows
				list {
					nodes {
						id
            			containerId
						title
						fid
						displayFid
						fileType
						latestEditor
						creationTime
						sort
					}
				}
			}
		}
	`;
	let ret = await got(document, true);
	if (!ret) return ret;
	let data = ret.data.operation.list.nodes.map(t => {
		return t;
	});
	return { msg: "ok", data, total: ret.data.operation.totalRows };
}

//fontend
export async function fileMetadata(params) {
	console.log({ params });
	const document = gql`
		{
			fileMetadata(filter: {}) {
				id
				accountId
				title
				fid
				displayFid
			}
		}
	`;
	let ret = await got(document, true);
	if (!ret) return ret;
	return ret.data.userList;
}
export async function NewFileMetadata(params) {
	console.log({ params });
	if (typeof params != "string") {
		let arr = ["{"];
		for (let k in params) {
			let v = params[k];
			if (typeof v == "number") {
				arr.push(`${k}:${v}`);
			} else {
				arr.push(`${k}:"${v}"`);
			}
		}
		arr.push("}");
		params = arr.join("\n");
	}
	const document = gql`
		mutation {
			newFileMetadata(fileMetadata: ${params})
		}
	`;
	let ret = await got(document, true);
	if (!ret) return ret;
	if (!ret.data.newFileMetadata) {
		ret.msg = "Save fail";
	}
	if (ret.msg != "ok") {
		antdHelper.alert(ret.msg);
		return ret;
	}
	return ret;
}
export async function updateFileMetadata(params) {
	console.log({ params });
	if (typeof params != "string") {
		let arr = ["{"];
		for (let k in params) {
			let v = params[k];
			if (typeof v == "number") {
				arr.push(`${k}:${v}`);
			} else {
				arr.push(`${k}:"${v}"`);
			}
		}
		arr.push("}");
		params = arr.join("\n");
	}
	const document = gql`
		mutation {
			updateFileMetadata(form: ${params})
		}
	`;
	// console.log(document);return;
	let ret = await got(document, true);
	if (!ret) return ret;
	if (!ret.data.updateFileMetadata) {
		ret.msg = "Save fail";
	}
	if (ret.msg != "ok") {
		antdHelper.alert(ret.msg);
		return ret;
	}
	return ret;
}
export async function deleteFileMetadata(id) {
	const document = gql`
		mutation {
			deleteFileMetadata(form: { id: ${id} })
		}
	`;
	let ret = await got(document, true);
	if (!ret) return ret;
	if (!ret.data.deleteFileMetadata) {
		ret.msg = "Delete fail";
	}
	return ret;
}
export async function discover(params) {
	let pagination = makePager(params);
	const document = gql`
  {
  getDiscover(filter: { fileType: ${params.filter} },${pagination}){
	totalRows
    list{
      nodes{
		id
        title
        fid
        displayFid
        fileTypeId
        creationTime
      }
  	}
  }
}
`;
	let ret = await got(document, true);
	if (!ret) return ret;
	let data = ret.data.getDiscover.list.nodes.map(t => {
		t.pic = formatPicUrl(t.displayFid);
		return t;
	});
	return { msg: "ok", data, total: ret.data.getDiscover.totalRows };
}
export async function fileDetail(fid) {
	const document = gql`
  {
  discover(filter: { fid: "${fid}" }, pagination:{after:"0", first:1}){
		totalRows
    list{
      nodes{
            id
            containerId
						title
						fid
						displayFid
						fileType
            shareLink
						latestEditor
						creationTime
						sort
      }
  	}
  }
}
`;
	let ret = await got(document, true);
	if (!ret) return ret;
	if (ret.msg != "ok") {
		console.log(ret);
		antdHelper.alert(ret.msg);
		return null;
	}
	console.log({ ret });
	let data = ret.data.discover.list.nodes.map(t => {
		return t;
	});
	return { msg: "ok", data: data[0] };
}
export async function rewards(params) {
	console.log({ params });
	let pagination = makePager(params);
	const document = gql`
    {
      rewards(${pagination}) {
        totalRewards
        discount
        totalRows
        rewards {
          nodes {
            accountId
            email
            invitedAccounts
            spend
            reward
          }
        }
      }
    }
  `;
	let ret = await got(document, true);
	if (!ret) return ret;
	let data = ret.data.rewards.rewards.nodes;
	if (data && data.length > 0) {
		data.forEach(t => {
			t.spend = formatBalanceStr(t.spend);
			t.reward = formatBalanceStr(t.reward);
		});
	}
	return {
		msg: "ok",
		data,
		total: ret.data.rewards.totalRows,
		totalRewards: formatBalanceStr(ret.data.rewards.totalRewards),
		discount: ret.data.rewards.discount
	};
}

// auth
export async function initiateAuth(identity, cessAddress = "") {
	let accountType = identityToInt(identity);
	if (cessAddress) {
		cessAddress = `address:"${cessAddress}"`;
	}
	const document = gql`
	mutation{
			initiateAuth(form: { identityOrEmail:"${identity}",accountType:${accountType},${cessAddress}})
		}
	`;
	if (accountType == 2) {
		setCessAddr(identity);
	}
	let ret = await got(document, true);
	if (!ret) return ret;
	return ret.data.initiateAuth;
}
export async function userLogin(identity, signedMessage) {
	identity = identity.trim();
	let accountType = identityToInt(identity);
	signedMessage = signedMessage.trim();

	let signedMessageKey = "signedMessage";
	if (accountType === 1) {
		signedMessageKey = "authCode";
	}
	const document = gql`
	mutation{
			login(form: { identityOrEmail:"${identity}",accountType:${accountType},${signedMessageKey}:"${signedMessage}"})
			{
				token
				id
				identity
				email
				address
				accountTypeId
				inviteCode
				isFirstLogin
			}
		}
	`;
	let ret = await got(document, true);
	if (ret?.msg == 'ok' && ret?.data?.login) {
		storeUserInfo(ret.data.login);
		if (accountType == 1 && ret.data.login.address) {
			setCessAddr(ret.data.login.address);
		}
	}
	return ret;
}
export async function authorizeForWallet(signedMsg, currentBlock) {
	const document = gql`mutation{authorizeGateway(
		form:{
			signedMsg:"${signedMsg}"
			currentBlock:${currentBlock}
		})
	}`;
	let ret = await got(document, true);
	if (ret?.msg == 'ok' && ret?.data?.authorizeGateway) {
		ret.msg = "ok"
	}
	return ret;
}
export async function authorize() {
	const document = gql`mutation{authorizeGateway}`;
	let ret = await got(document, true);
	if (ret?.msg == 'ok' && ret?.data?.authorizeGateway) {
		ret.msg = "ok"
	}
	return ret;
}

//email login
export async function applyInviteCode(identity, inviteCode) {
	const document = gql`
		mutation{
			applyInviteCode(form: { identity:"${identity}",inviteCode:"${inviteCode}"})
		}
	`;
	let ret = await got(document, true);
	return ret;
}
export async function verifyEmailAndSendBindCode(email) {
	const document = gql`
    mutation {
		initiateEmailBind(email: "${email}")
    }
  `;
	let ret = await got(document, true);
	return ret;
}
export async function verifyEmail(authCode) {
	const document = gql`
    mutation {
		bindEmail(authCode: "${authCode}")
    }
  `;
	let ret = await got(document, true);
	return ret;
}
export async function updateAccount(entity) {
	return { msg: "ok" };
	let arr = [];
	for (let k of Object.keys(entity)) {
		let v = entity[k];
		if (typeof v == "number") {
			arr.push(`${k}:${v}`);
		} else {
			arr.push(`${k}:"${v}"`);
		}
	}
	let form = arr.join(",");
	const document = gql`
		mutation{
			updateAccount(form: {${form}})
		}
	`;
	let ret = await got(document, true);
	return ret;
}

//space
export async function territoryCreat(territoryName, gibCount, days, token) {
	if (gibCount) {
		gibCount = "space:" + gibCount;
	} else {
		gibCount = "";
	}
	if (days) {
		days = "days:" + days;
	} else {
		days = "";
	}
	if (token) {
		token = 'token:"' + token + '"';
	} else {
		token = "";
	}
	const document = gql`
		mutation{
			newTerritory(form: { name:"${territoryName}" ${gibCount} ${days} ${token}})
		}
	`;
	let ret = await got(document, true);
	return ret;
}
export async function territoryExtendSize(territoryName, gibCount) {
	if (gibCount) {
		gibCount = "space:" + gibCount;
	} else {
		gibCount = "";
	}
	const document = gql`
		mutation{
			extendTerritorySpace(form: { name:"${territoryName}" ${gibCount}})
		}
	`;
	let ret = await got(document, true);
	return ret;
}
export async function territoryExtendTime(territoryName, days) {
	if (days) {
		days = "days:" + days;
	} else {
		days = "";
	}
	const document = gql`
		mutation{
			extendTerritoryTime(form: { name:"${territoryName}" ${days}})
		}
	`;
	let ret = await got(document, true);
	return ret;
}
export async function territoryReactivate(territoryName, days) {
	if (days) {
		days = "days:" + days;
	} else {
		days = "";
	}
	const document = gql`
		mutation{
			reactivateTerritory(form: { name:"${territoryName}" ${days}})
		}
	`;
	let ret = await got(document, true);
	return ret;
}
export async function territoryRename(oldName, newName) {
	const document = gql`
		mutation{
			renameTerritory(form: { oldName:"${oldName}" newName:"${newName}"})
		}
	`;
	let ret = await got(document, true);
	return ret;
}
export async function territoryRefresh() {
	const document = gql`
		mutation{
			refreshTerritory
		}
	`;
	let ret = await got(document, true);
	return ret;
}

//Container
export async function getContainer(parentId, territoryId) {
	console.log({ parentId, territoryId });
	if (parentId) {
		parentId = "parentId:" + parentId;
	} else {
		parentId = "";
	}
	if (territoryId) {
		territoryId = "territoryId:" + territoryId;
	} else {
		territoryId = "";
	}
	const document = gql`
		{
			getContainer(filter: {${parentId} ${territoryId}}) {
				id
				name
				parentId
				territoryId						
			}
		}
	`;
	let ret = await got(document, true);
	if (ret && ret.msg == "ok" && ret.data?.getContainer) {
		let info = ret.data.getContainer;
		ret.data = info;
	}
	return ret;
}
export async function getAccountContainers() {
	const document = gql`
		{
			getAccountContainers{
				id
				name
				parentId
				territoryId
			}
	  	}
	`;
	let ret = await got(document, true);
	if (ret && ret.msg == "ok" && ret.data?.getAccountContainers) {
		let info = ret.data.getAccountContainers;
		ret.data = info;
	}
	return ret;
}
export async function newContainer(name, territoryId, parentId) {
	if (territoryId != parentId && parentId) {
		parentId = `parentId:${parentId}`;
	} else {
		parentId = "";
	}
	const document = gql`
		mutation{
			newContainer(form: {name:"${name}" territoryId:${territoryId} ${parentId}})
		}
	`;
	let ret = await got(document, true);
	return ret;
}
export async function deleteContainer(containerId) {
	const document = gql`
		mutation{
			deleteContainer(containerId:${containerId})
		}
	`;
	let ret = await got(document, true);
	return ret;
}
export async function renameContainer(id, newName) {
	const document = gql`
		mutation{
			renameContainer(form: {id:${id} name:"${newName}"})
		}
	`;
	let ret = await got(document, true);
	return ret;
}

//file
export async function getMyFiles(territoryId, containerId, title, fid) {
	console.log({ territoryId, containerId, title, fid });
	let pagination = makePager({ pageindex: 1, pagesize: 1000 });
	if (title) {
		title = `title:"${title}"`;
	} else {
		title = "";
	}
	if (fid) {
		fid = `fid:"${fid}"`;
	} else {
		fid = "";
	}
	if (containerId) {
		containerId = `containerId:${containerId}`;
	} else {
		containerId = "";
	}
	if (territoryId) {
		territoryId = `territoryId:${territoryId}`;
	} else {
		territoryId = "";
	}
	const document = gql`
    {
		getFileMap(filter: {${title} ${fid} ${territoryId} ${containerId}},${pagination}) {
			totalRows
			list {
				nodes {
					id
					containerId
					territoryId
					title
					fid
					fileTypeId
					shareLink
					creationTime
					fileExt
				}
			}        
      }
    }
  `;
	let ret = await got(document, true);
	if (!ret || ret.msg != "ok") return ret;
	if (ret.data?.getFileMap?.list?.nodes) {
		let info = ret.data.getFileMap.list.nodes;
		// info?.files?.forEach(t => {
		// 	t.name = t.title;
		// 	t.fileSizeStr = formatterSizeStr(t.fileSize);
		// });
		ret.data = info;
	}
	return ret;
}
export async function getFileMapByShareLink(shareid) {
	const document = gql`
    {
		getFileMapByShareLink(shareLink:"${shareid}") {
			id
			containerId
			territoryId
			title
			fid
			fileTypeId
			shareLink
			creationTime
			fileExt
      }
    }
  `;
	let ret = await got(document, true);
	if (!ret || ret.msg != "ok") return ret;
	if (ret.data?.getFileMapByShareLink) {
		ret.data = [ret.data.getFileMapByShareLink];
	}
	return ret;
}
export async function newFileMap(fid, title, territoryId, containerId) {
	if (!fid || fid.length < 20) {
		antdHelper.alertError("Fid format error");
	}
	let fileType = getFileTypeId(title);
	let fileExt = getFileExt(title);
	if (containerId) {
		containerId = `containerId:${containerId}`;
	} else {
		containerId = "";
	}

	const document = gql`
		mutation{
			newFileMap(form: { fid:"${fid}",title:"${title}",territoryId:${territoryId},${containerId},fileType:${fileType},fileExt:"${fileExt}"})
		}
	`;
	let ret = await got(document, true);
	return ret;
}
export async function updateFileMap(territoryId, id, containerId) {
	if (isNaN(containerId)) {
		containerId = "";
	} else {
		containerId = "containerId:" + containerId;
	}
	const document = gql`
		mutation{
			updateFileMap(form: { id:${id},territoryId:${territoryId}, ${containerId}})
		}
	`;
	let ret = await got(document, true);
	return ret;
}
export async function deleteFileMap(id) {
	const document = gql`
		mutation{
			deleteFileMap(form: { id:${id}})
		}
	`;
	let ret = await got(document, true);
	return ret;
}
export async function fileMapRefresh() {
	const document = gql`
		mutation{
			refreshFileMap
		}
	`;
	let ret = await got(document, true);
	return ret;
}

//Sign
export async function getSignMessage(msg) {
	const document = gql`
	{
		getSignMessage(message: "${msg}"){
		message
		address
		signedMsg
	  }
	}`;
	let ret = await got(document, true);
	if (!ret || ret.msg != "ok") {
		return ret;
	}
	ret.msg = ret.data.getSignMessage ? "ok" : "fail";
	return ret;
}
